package cn.buk.qms.web;

import cn.buk.common.Constant;
import cn.buk.common.JsonResult;
import cn.buk.qms.captcha.CaptchaException;
import cn.buk.qms.captcha.CaptchaService;
import cn.buk.tms.dto.DtoLoginStatus;
import cn.buk.tms.entity.misc.LoginHistory;
import cn.buk.tms.entity.misc.RolePrivilege;
import cn.buk.tms.entity.misc.User;
import cn.buk.qms.service.EnterpriseService;
import cn.buk.qms.service.SmsService;
import cn.buk.qms.service.UserService;
import cn.buk.common.util.CheckUtil;
import cn.buk.common.util.DateUtil;
import cn.buk.common.util.VerifyCodeUtil;
import com.google.code.kaptcha.Constants;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.core.AuthenticationException;
import org.springframework.web.bind.annotation.*;

import jakarta.servlet.http.Cookie;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpSession;

import java.util.Date;
import java.util.List;

import static cn.buk.qms.HttpServletUtil.getIpAddr;
import static cn.buk.qms.session.LoginUtil.execLoginProcess;

/**
 * @author yfdai
 * @date 2017-07-15
 */
@RestController
public class LoginController extends BaseController {

    private static final Logger logger = LogManager.getLogger(LoginController.class);

    @Value("${owner_enterprise_id}")
    private int ownerId;

    @Autowired
    private CaptchaService captchaService;

    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private UserService userService;

    @Autowired
    private SmsService smsService;

    @Autowired
    private EnterpriseService enterpriseService;


    /**
     * 从cookie中获取captchaId
     *
     * @param cookies
     * @return
     */
    private String getCaptchaId(Cookie[] cookies) {
        if (cookies == null) {
            return null;
        }

        String captchaCookieId = null;
        for (Cookie cookie : cookies) {
            if (Constants.KAPTCHA_SESSION_KEY.equalsIgnoreCase(cookie.getName())) {
                captchaCookieId = cookie.getValue();
                break;
            }
        }

        return captchaCookieId;
    }

    @RequestMapping({"/logout.do", "/logout0"})
    public JsonResult logout(HttpServletRequest request) {
        HttpSession session = request.getSession();
        session.invalidate();

        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus("OK");

        return jsonResult;
    }

    @PostMapping(value = {"/login", "/ajaxLogin.do"})
    public DtoLoginStatus login(HttpServletRequest request,
                                @RequestParam(value = "username", defaultValue = "") final String username,
                                @RequestParam(value = "password", required = false) final String password,
                                @RequestParam(value = "md5password", required = false) final String md5password,
                                @RequestParam(value = "captchaValue", required = false) final String captchaValue,
                                @RequestParam(value = "openid", defaultValue = "") final String openid) throws Exception {
        if (username == null) {
            throw new Exception("Pls input username first.");
        }

        final String remoteAddress = getIpAddr(request);
        logger.info("username,password,captcha, remoteIp:" + username + ", " + password + ", " + captchaValue + ", " + remoteAddress);

        DtoLoginStatus jsonResult = new DtoLoginStatus();
        jsonResult.setStatus("ER");

        if (username.length() < 1) {
            jsonResult.setErrmsg("请输入用户名和口令");
            return jsonResult;
        }

        if ((password == null || password.length() < 1) && (md5password == null)) {
            jsonResult.setErrmsg("请输入用户名和口令");
            return jsonResult;
        }


        HttpSession session = request.getSession();

        // 本机登录不需要验证码（用于前端自动化测试）
        if (!"127.0.0.1".equalsIgnoreCase(remoteAddress)) {
            final String captchaKey = getCaptchaId(request.getCookies());

            //微信用户
            if (openid == null || openid.trim().length() == 0) {
                if (captchaValue == null || captchaValue.length() < 1) {
                    jsonResult.setErrmsg("请输入验证码");
                    return jsonResult;
                }

                boolean captchaOk = false;
                try {
                    captchaOk = captchaService.validateCaptcha(captchaKey, captchaValue);
                } catch (CaptchaException e) {
                    logger.info(e.getMessage());
                }

                if (!captchaOk) {
                    jsonResult.setErrmsg("请输入正确的验证码");
                    return jsonResult;
                }
            }
        }


        User u = userService.getUserByUsername(username.trim());

        if (u == null && CheckUtil.isMobileNo(username)) {
            //使用手机号登录的
            List<User> users = userService.searchUsersByMobile(username);
            if (!users.isEmpty()) {
                logger.info("login by mobile(" + username + "), search " + users.size() + " user.");
                u = users.get(0);
            }
        }

        if (u == null) {
            logger.info("u == null, " + username);
            jsonResult.setErrmsg("请检查用户名和口令");
            return jsonResult;
        }

        //将传过来的明文密码md5，或传过来的就是md5后的密码
        final String currentPwd = md5password == null ? VerifyCodeUtil.MD5(password) : md5password;
        logger.info("{}, {}, {}.", md5password, password, currentPwd);

        final String savePwd = u.getMd5Password() == null ? VerifyCodeUtil.MD5(u.getPassword()) : u.getMd5Password();

        if (!currentPwd.equalsIgnoreCase(savePwd)) {
            jsonResult.setErrmsg("请检查登录密码");
            return jsonResult;
        }

        if (u.getStatus() == User.USER_STATUS_BANNED) {
            logger.error(username.trim() + ": is banned.");
            jsonResult.setErrmsg("账号已停用");

            return jsonResult;
        }


        try {
            logger.info("{}, {}, {}.", u.getUsername(), password, currentPwd);
            execLoginProcess(authenticationManager, session, u.getId(), u.getEnterprise().getId(), u.getUsername(), currentPwd, u.getEmpname());
        } catch (AuthenticationException ex) {
            ex.printStackTrace();
            jsonResult.setErrmsg("用户名或密码错误(" + ex.getMessage() + ").");
            return jsonResult;
        }

        final int enterpriseId = u.getEnterprise().getId();


        // 获取该企业的付费有效期
        Date expireDate = enterpriseService.getEntExpireDate(enterpriseId);

        if (expireDate != null) {
            jsonResult.setExpireDate(expireDate);
            final int expiredDays = DateUtil.getDaySpan(expireDate, DateUtil.getCurDate());
            jsonResult.setExpireDays(expiredDays);

            if (expiredDays < 0 && u.getId() != enterpriseId) {
                logger.warn("Member(" + u.getUsername() + ") is expired.");
                jsonResult.setErrmsg("会员已过期，请用主账号登录！");
                return jsonResult;
            }
        }

        LoginHistory h = new LoginHistory();
        h.setEnterpriseId(enterpriseId);
        h.setIpaddr(remoteAddress);
        h.setFunctionId(Constant.FUNCTION_SYSTEM_LOGIN);
        h.setUsername(u.getUsername());
        h.setMemo(u.getUsername() + " login from " + remoteAddress);
        // userService.createLoginHistory(h);

        final String token0 = u.getUsername() + "," + u.getId() + "," + enterpriseId + "," + remoteAddress + ", " + DateUtil.getCurDateTime().getTime();
        logger.info(token0);
        final String token = VerifyCodeUtil.MD5(token0);

        jsonResult.setStatus("OK");
        jsonResult.setUserId(u.getId());
        jsonResult.setUsername(u.getUsername());
        jsonResult.setAvatar(u.getAvatar());
        jsonResult.setFullName(u.getEmpname());
        jsonResult.setEnterpriseId(enterpriseId);
        jsonResult.setToken(token);
        jsonResult.setPassword(savePwd);

        //获取携程联盟的站点ID
        final String sid = enterpriseService.getCtripAllianceSiteId(enterpriseId);
        jsonResult.setSid(sid);

        //redmine url
        jsonResult.setRedmineUrl(enterpriseService.getRedmineUrl(0));

        //保存token到redis中
        userService.saveToken(jsonResult);
        jsonResult.setStatus("OK");
        jsonResult.setPassword("");

        return jsonResult;
    }

    /**
     * 企业微信二次验证
     */
    @RequestMapping(value = "/public/validateWwUser")
    public JsonResult login(HttpServletRequest request,
                            @RequestParam(value = "username") final String username,
                            @RequestParam(value = "password") final String password,
                            @RequestParam(value = "captchaValue") final String captchaValue,
                            @RequestParam(value = "eid", defaultValue = "0") final int enterpriseId,
                            @RequestParam(value = "wwCode", defaultValue = "") final String wwCode) {

        final String captchaKey = getCaptchaId(request.getCookies());

        //校验验证码
        if (captchaValue == null || captchaValue.length() < 1) {
            return JsonResult.createJsonResult(-1, "请输入验证码");
        }

        boolean captchaOk = false;
        try {
            captchaOk = captchaService.validateCaptcha(captchaKey, captchaValue);
        } catch (CaptchaException e) {
            logger.info(e.getMessage());
        }

        if (!captchaOk) {
            return JsonResult.createJsonResult(-2, "请输入正确的验证码");
        }

        if (username == null || username.length() < 1 || password.length() < 0) {
            return JsonResult.createJsonResult(-3, "请输入用户名和口令");
        }


        User u = userService.getUserByUsername(username.trim());

        if (u == null || u.getEnterpriseId() != enterpriseId) {
            return JsonResult.createJsonResult(-4, "无此用户或系统参数设置错误");
        }

        if (password.compareTo(u.getPassword()) != 0) {
            logger.error(username.trim() + ": password is not correct. (" + password + ")");
            return JsonResult.createJsonResult(-5, "请检查用户名和口令");
        }

        final String remoteAddress = getIpAddr(request);

        return enterpriseService.validateWwUser(u, wwCode, remoteAddress);
    }

    /**
     * 租户注册，注册成功则为该租户生成一个root账号
     *
     * @param request
     * @param user
     * @param captchaValue
     * @param invitationCode
     * @return
     */
    @RequestMapping("/register.do")
    public JsonResult register(HttpServletRequest request,
                               @ModelAttribute("user") User user,
                               @RequestParam(value = "captchaValue") final String captchaValue,
                               @RequestParam(value = "invitationCode", defaultValue = "") final String invitationCode
    ) {

        if (user.getUsername().length() == 0 || user.getMobileNo().length() == 0
                || user.getMobileNo().length() != 11) {
            return JsonResult.createJsonResult(-1, "用户名、手机号是必需的");
        }

        final String remoteAddress = getIpAddr(request);

        logger.info(
                "register: " + remoteAddress + ", " + user.getMobileNo() + ", " + user.getUsername());

        if (captchaValue == null || captchaValue.length() == 0) {
            return JsonResult.createJsonResult(-2, "验证码需要填写");
        }

        final String captchaKey = getCaptchaId(request.getCookies());

        try {
            if (captchaKey == null) {
                logger.error("captchaKey is null.");
                return JsonResult.createJsonResult(-3, "Pls input captcha key.");
            } else if (!captchaService.validateCaptcha(captchaKey, captchaValue)) {
                logger.warn("You input wrong captchaCode.");
                return JsonResult.createJsonResult(-4, "验证码不正确");
            }
        } catch (CaptchaException e) {
            logger.error(e.getMessage());
        }

        return userService.registerNewTenancyUser(user, invitationCode);
    }


    /**
     * 发送重置密码的校验短信
     *
     * @return
     */
    @RequestMapping("/sendResetPasswordSms.do")
    public JsonResult sendResetPasswordSms(HttpServletRequest request,
                                           @RequestParam("mobile") String mobile,
                                           @RequestParam("captchaValue") String captchaValue) {
        if (captchaValue == null || captchaValue.length() == 0) {
            return JsonResult.createJsonResult(-2, "请输入验证码");
        } else {
            try {
                final String captchaKey = getCaptchaId(request.getCookies());

                if (captchaKey == null) {
                    return JsonResult.createJsonResult(-3, "验证码不正确");

                } else if (!captchaService.validateCaptcha(captchaKey, captchaValue)) {
                    return JsonResult.createJsonResult(-4, "验证码不正确");
                }
            } catch (CaptchaException e) {
                return JsonResult.createJsonResult(-5, "验证码不正确");
            }
        }

        if (!CheckUtil.isMobileNo(mobile)) {
            return JsonResult.createJsonResult(-2, "手机号格式不正确");
        }

        //通过手机号找用户
        User user = userService.getUserByMobile(this.ownerId, mobile, User.USER_TYPE_PSG);
        if (user == null) {
            return JsonResult.createJsonResult(-1, "未找到此手机对应的用户");
        }

        //发送短信
        String verifyCode = VerifyCodeUtil.getMobileVerifyCode(mobile);
        String smsContent = "验证码：" + verifyCode;

        int smsStatus = smsService.sendSms(mobile, smsContent);

        if (smsStatus == 1) {
            logger.info("sms successfully: " + user.getMobileNo() + "," + smsContent);
        }

        setSessionValue(request, "FIND_PASSWORD_MOBILE", mobile);
        setSessionValue(request, "FIND_PASSWORD_VERIFIED_CODE", verifyCode);
        setSessionValue(request, "FIND_PASSWORD_USER_ID", user.getId() + "");

        return JsonResult.createJsonResult(smsStatus, "验证码已发送");
    }

    /**
     * 重置密码
     *
     * @return
     */
    @RequestMapping("/resetPassword.do")
    public JsonResult resetPassword(HttpServletRequest request,
                                    @RequestParam("mobile") String mobile,
                                    @RequestParam("smsVerifyCode") String smsVerifyCode,
                                    @RequestParam("newPassword") String newPassword,
                                    @RequestParam("confirmPassword") String confirmPassword
    ) {

        String verifyCode = getSessionValue(request, "FIND_PASSWORD_VERIFIED_CODE");
        if (smsVerifyCode == null || smsVerifyCode.trim().length() == 0 || verifyCode.length() == 0 || !verifyCode.equalsIgnoreCase(smsVerifyCode)) {
            return JsonResult.createJsonResult(-1, "验证码错误");
        }

        String mobile0 = getSessionValue(request, "FIND_PASSWORD_MOBILE");
        if (mobile == null || !mobile.equalsIgnoreCase(mobile0)) {
            return JsonResult.createJsonResult(-2, "意外，请重新找回密码");
        }

        if (newPassword == null || newPassword.length() < 3 || !newPassword.equalsIgnoreCase(confirmPassword)) {
            return JsonResult.createJsonResult(-3, "密码长度需要大于3位，并于确认密码保持一致");
        }

        String tmp = getSessionValue(request, "FIND_PASSWORD_USER_ID");
        int userId = 0;
        try {
            userId = Integer.parseInt(tmp);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        User user = userService.getUserById(userId);
        if (user == null || !user.getMobileNo().equalsIgnoreCase(mobile)) {
            return JsonResult.createJsonResult(-4, "未找到符合要求的用户");
        }

        int status = userService.resetPassword(userId, newPassword);
        if (status != 1) {
            return JsonResult.createJsonResult(-5, "重置密码时出现意外，请再试一次！");
        }

        JsonResult jsonResult = new JsonResult();
        jsonResult.setStatus("OK");
        jsonResult.setDesc(user.getUsername());

        return jsonResult;
    }

    /**
     * 查找当前用户拥有的权限
     */
    @RequestMapping("/privileges")
    public List<RolePrivilege> searchMyPrivileges(HttpServletRequest request) {
        final int userId = getUserId(request);
        final int enterpriseId = getEnterpriseId(request);

        try {
            logger.info("{}, {}.", enterpriseId, userId);
            return userService.searchPrivileges(enterpriseId, userId);
        } catch(Exception ex) {
            ex.printStackTrace();
            return null;
        }
        
    }

    @RequestMapping({"/checkLoginStatus", "/chklogin"})
    public DtoLoginStatus checkLoginStatus(HttpServletRequest request) {


        DtoLoginStatus jsonResult = new DtoLoginStatus();
        jsonResult.setStatus("ER");

        final String username = getUsername(request);


        final String remoteAddress = getIpAddr(request);
        logger.info("username, remoteIp:{}, {}", username, remoteAddress);

        if (username != null && username.length() > 0) {

            User u = userService.getUserByUsername(username.trim());

            jsonResult.setStatus("OK");
            jsonResult.setUsername(username);
            if (u != null) {
                jsonResult.setAvatar(u.getAvatar());
            }
            jsonResult.setUserId(getUserId(request));

            final int enterpriseId = getEnterpriseId(request);
            jsonResult.setEnterpriseId(enterpriseId);

            final var expiredDate = enterpriseService.getEntExpireDate(enterpriseId);
            if (expiredDate != null) {
                jsonResult.setExpireDate(expiredDate);
                jsonResult.setExpireDays(DateUtil.getPastDays(expiredDate, DateUtil.getCurDate()));
            }

            //获取携程联盟的站点ID
            final String sid = enterpriseService.getCtripAllianceSiteId(enterpriseId);
            jsonResult.setSid(sid);

            //redmine url
            jsonResult.setRedmineUrl(enterpriseService.getRedmineUrl(0));
        }

        return jsonResult;
    }
}
